/**
  ******************************************************************************
  * @author     Chris
  * @since      2024/6/13 14:24
  *
  * @file       pd_timer_pwm.c
  * @brief      TimerPWM peripheral driver.
  *
  * @note       This file contains the peripheral driver for the TimerPWM.
  *
  * @warning    None.
  ******************************************************************************
  * Change Logs:
  *   Date          Author       Notes
  *   2024/6/13     Chris        the first version
  *
  ******************************************************************************
  */

#include <stm32f4xx_ll_tim.h>
#include "pd_timer_pwm.h"

static void TimerPWM_init_(const TimerPWM *this) {
    if (LL_TIM_IsEnabledCounter(this->timer->TIMx)) {
        // Update Timer channel if Timer is running.
        TimerOC_init(this->timerOC);
        return;
    }

    // Timer Base Unit
    Timer_init(this->timer);

    // Set Internal Clock Source
    LL_TIM_SetClockSource(this->timer->TIMx, LL_TIM_CLOCKSOURCE_INTERNAL);

    // Set Timer Output Compare Unit
    TimerOC_init(this->timerOC);

    LL_TIM_EnableCounter(this->timer->TIMx);
}

/**
 * @brief   set duty of timer by changing the CCR value.
 *
 * @note    PWM duty = CCR / (ARR + 1)
 * @param   this    Timer PWM instance
 * @param   val     CCR value
 * @param   channel This parameter can be one of the following values:
 *          @arg @ref LL_TIM_CHANNEL_CH1
 *          @arg @ref LL_TIM_CHANNEL_CH2
 *          @arg @ref LL_TIM_CHANNEL_CH3
 *          @arg @ref LL_TIM_CHANNEL_CH4
 *          @arg @ref LL_TIM_CHANNEL_CH5
 *          @arg @ref LL_TIM_CHANNEL_CH6
 * @retval  None
 */
static void TimerPWM_setDuty_(const TimerPWM *this, const uint32_t channel, const uint32_t val) {
    switch (channel) {
        case LL_TIM_CHANNEL_CH1: LL_TIM_OC_SetCompareCH1(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH2: LL_TIM_OC_SetCompareCH2(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH3: LL_TIM_OC_SetCompareCH3(this->timer->TIMx, val);
            break;
        case LL_TIM_CHANNEL_CH4: LL_TIM_OC_SetCompareCH4(this->timer->TIMx, val);
            break;
        default: break;
    }
}

void TimerPWM_constructor(TimerPWM *this, Timer *timer, TimerOC *timerOC) {
    static struct TimerPWMVtbl vtbl = {
        .init = &TimerPWM_init_,
        .set_pwm_duty = &TimerPWM_setDuty_,
    };

    this->vptr = &vtbl;
    this->timer = timer;
    this->timerOC = timerOC;
}
